import { refDebounced, useEventListener } from '@peng_kai/kit/libs/vueuse';
import { createApp } from 'vue';
import { useLocale } from '~/modules/locale';

interface TGameMessages {
  updateBalance: undefined;
  deposit: undefined;
  loaded: any;
  updateGameState: { state: 'idle' | 'playing' };
  showUser: { id: string };
  shareGameRecord: { gameCode: string; orderNo: string };
  toPlay: { code: string };
  changeLiveChartEnabled: { enabled: boolean };
  changeHotKeyState: { state: boolean };

  addMyLog: any;
  addAllLog: any;
  login: any;
  showGameRecord: { gameCode: string; orderNo: string };
  resetWinSize: { width: number; height: number };
  popupRect: DOMRect;
  refresh: undefined;
}

export const SELF_GAME_IFRAME_ID = 'self-game-iframe';
// 来自游戏的消息前缀
const GAME_PM_PREFIX = 'g9Game';
// 发给游戏的消息前缀（来自游戏的宿主消息）
const GAME_HOST_PM_PREFIX = 'g9GameHost';

function getIframe() {
  const iframe = document.getElementById(SELF_GAME_IFRAME_ID) as (HTMLIFrameElement | undefined);
  return iframe;
}

function createPM<N extends string, D>(name: N, _dataType?: D) {
  return {
    [name]: (data: D) => {
      getIframe()?.contentWindow?.postMessage({ type: `${GAME_HOST_PM_PREFIX}:${name}`, data }, '*');
    },
  } as Record<typeof name, D extends undefined ? () => void : (data: D) => void>;
}

export const emitGamePM = {
  ...createPM('updateCurrency', {} as { type: 'init' | 'currency' | 'balance'; currency: string }),
  ...createPM('updateUser', undefined),
  ...createPM('changeLiveChartEnabled', {} as { enabled: boolean }),
  ...createPM('keydown', {} as { key: string;code: string }),
};

export function useOnGamePM<E extends keyof TGameMessages>(event: E, listener: (ev: TGameMessages[E]) => void) {
  useEventListener(window, 'message', (ev) => {
    const type: string = ev.data?.type;
    const data = ev.data?.data;

    if (type === `${GAME_PM_PREFIX}:${event}`)
      listener(data);
  });
}

export function useLoadGameScript(gameCode: MaybeRef<string>) {
  const isDev = import.meta.env.DEV && location.search.includes('dev=1');
  const isLoading = ref(true);
  const version = envs.isTestHost ? Date.now() : import.meta.env.VERSION;
  const src = computed(() => isDev
    ? `/${toValue(gameCode)}.dev.js?t=${version}`
    : `${location.origin}/g/${toValue(gameCode)}/index.js?t=${version}`,
  );

  const hasScript = (src: string) => !!document.querySelector(`script[src="${src}"]`);

  watch(src, (src) => {
    if (hasScript(src)) {
      isLoading.value = false;
      return;
    }

    const script = document.createElement('script');
    script.src = src;
    script.async = true;
    script.defer = true;
    script.onload = () => {
      isLoading.value = false;
    };
    document.body.appendChild(script);
  }, { immediate: true });

  return isLoading;
}

export function useLoadGameElement(gameCode: MaybeRefOrGetter<string>, elementName: 'play' | 'record-detail') {
  const { locale } = useLocale();
  const isAuthed = useAuthed();
  const gameCodeRef = toRef(gameCode);
  const gameLaunchQry = useQuery({
    gcTime: 0,
    queryKey: [apis.apiGametLaunch.id, gameCodeRef, isAuthed, elementName],
    queryFn: () => apis.apiGametLaunch({ game_code: gameCodeRef.value }),
  });
  const isScriptLoading = useLoadGameScript(gameCodeRef);
  const isGameLoading = useBoolean(true);
  const displayLoading = computed(() => gameLaunchQry.isLoading.value || isScriptLoading.value || isGameLoading.is);
  const displayGameElement = computed(() => !isScriptLoading.value && (isAuthed.value ? !!gameLaunchQry.data.value?.game_token : !!gameLaunchQry.data.value));
  const gameElementRef = ref<HTMLElement>();
  const GameElement = computed(() => {
    const code = toValue(gameCode);
    const fullName = `g9-${code.replace(/[^a-zA-Z0-9]/g, '').toLowerCase()}-${elementName}`;

    return displayGameElement.value ? markRaw(h(fullName)) : h('div');
  });
  const gameElementPresetProps = computed(() => {
    const gameToken = gameLaunchQry.data.value?.game_token;
    const _locale = locale.value === 'pt-BR' ? 'pt-PT' : locale.value;
    return {
      ref: (ele: any) => gameElementRef.value = ele,
      key: gameToken,
      token: gameToken,
      // TODO: 临时解决方案，后续需要游戏支持
      locale: _locale,
    };
  });

  // TODO：刷新路由后不会触发游戏的loaded事件，暂时使用页面刷新
  useEventListener(gameElementRef, 'loaded', () => isGameLoading.setFalse());

  return { GameElement, gameElementRef, displayLoading, gameElementPresetProps };
}
